/**
 * ReportGear(2011)
 */
package com.reportgear.designer.pane.headerfooter;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.SystemColor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JToolBar;
import javax.swing.JViewport;
import javax.swing.Scrollable;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import com.reportgear.core.swing.pane.base.JBaseDialog;
import com.reportgear.core.util.UnitUtils;
import com.reportgear.report.model.headerfooter.GroupPageNumHFElement;
import com.reportgear.report.model.headerfooter.GroupTotalPagesHFElement;
import com.reportgear.report.model.headerfooter.HFElement;
import com.reportgear.report.model.headerfooter.NewLineHFElement;
import com.reportgear.report.model.headerfooter.PageNumHFElement;
import com.reportgear.report.model.headerfooter.ReportHF;
import com.reportgear.report.model.headerfooter.TextHFElement;
import com.reportgear.report.model.headerfooter.TotalPagesHFElement;
import com.reportgear.report.model.headerfooter.editor.ElementEditor;
import com.reportgear.report.view.grid.util.GraphHelper;
import com.reportgear.swing.util.GuiUtils;

/**
 * 面板-页眉页脚-编辑
 * 
 * @version 1.0 2011-4-22
 * @author <a herf="lexloo@gmail.com">lexloo</a>
 * @since Report 1.0
 */
public class HeaderFooterEditPane extends JPanel {
	/**
	 * UID
	 */
	private static final long serialVersionUID = 3452186905377343652L;
	private HFPreviewPane hfPreviewPane;
	private HFContainer leftHFContainer;
	private HFContainer centerHFContainer;
	private HFContainer rightHFContainer;
	private HFContainer currentHFContainer;
	private AdjustHeightPane headFootUnitFieldPane;
	private double hfWidth = 500;

	// 页脚页眉高度
	private double hfHeight = 0;

	private ActionListener insertActionListener = new ActionListener() {
		public void actionPerformed(ActionEvent evt) {
			HFElement el;
			HFInsertButton insertBtn = (HFInsertButton) evt.getSource();
			el = (HFElement) insertBtn.getHFElement().clone();
			ElementEditor editor = el.getEditor();

			if (editor != null) {
				editor.populate(el);
				if (JBaseDialog.RESULT_OK == editor.showInDialog(HeaderFooterEditPane.this)) {
					el = editor.update();
				}
			}

			HFComponent c = new HFComponent(el);

			currentHFContainer.addHFComponent(c);
			refresh();
		}
	};

	private MouseListener focusMouseListener = new MouseAdapter() {
		public void mousePressed(MouseEvent evt) {
			Object src = evt.getSource();
			if (!(src instanceof HFContainer)) {
				return;
			}

			HFContainer hfc = (HFContainer) src;

			if (!hfc.isEnabled()) {
				return;
			}

			hfc.requestFocus();

			leftHFContainer.setBorder(null);
			centerHFContainer.setBorder(null);
			rightHFContainer.setBorder(null);

			setCurrentHFContainer(hfc);
		}
	};

	public HeaderFooterEditPane() {
		initComponents();
	}

	private void initComponents() {
		setLayout(new BorderLayout());

		JPanel paneContainer = new JPanel();
		add(paneContainer, BorderLayout.CENTER);
		paneContainer.setLayout(new BorderLayout(0, 4));

		JPanel panePreview = new JPanel();
		paneContainer.add(panePreview, BorderLayout.CENTER);
		panePreview.setLayout(new BorderLayout());
		panePreview.setBorder(BorderFactory.createTitledBorder("预览"));
		this.hfPreviewPane = new HFPreviewPane();
		panePreview.add(new JScrollPane(this.hfPreviewPane), BorderLayout.CENTER);

		JPanel paneToolbar = new JPanel();
		paneContainer.add(paneToolbar, BorderLayout.NORTH);
		paneToolbar.setLayout(new BorderLayout(0, 2));

		JToolBar tbrTools = new JToolBar();
		paneToolbar.add(tbrTools, BorderLayout.NORTH);
		tbrTools.setFloatable(false);

		Dimension dimSep = new Dimension(6, 22);
		tbrTools.add(createHFInsertButton(new TextHFElement()));
		tbrTools.addSeparator(dimSep);
		tbrTools.add(createHFInsertButton(new PageNumHFElement()));
		tbrTools.add(createHFInsertButton(new TotalPagesHFElement()));
		tbrTools.addSeparator(dimSep);
		tbrTools.add(createHFInsertButton(new GroupPageNumHFElement()));
		tbrTools.add(createHFInsertButton(new GroupTotalPagesHFElement()));
		tbrTools.addSeparator(dimSep);
		tbrTools.add(createHFInsertButton(new NewLineHFElement()));
		tbrTools.addSeparator(dimSep);

		JPanel paneHeight = new JPanel(new FlowLayout(FlowLayout.LEFT));
		this.headFootUnitFieldPane = new AdjustHeightPane();
		paneHeight.add(new JLabel("高度:"));
		paneHeight.add(this.headFootUnitFieldPane);
		tbrTools.add(paneHeight);

		JPanel paneElementContainer = new JPanel();
		paneToolbar.add(paneElementContainer, BorderLayout.CENTER);
		paneElementContainer.setPreferredSize(new Dimension(paneContainer.getPreferredSize().width, 120));
		paneElementContainer.setLayout(new GridLayout(1, 3, 4, 4));

		ChangeListener contentChangeListener = new ChangeListener() {
			public void stateChanged(ChangeEvent paramChangeEvent) {
				HeaderFooterEditPane.this.refresh();
			}
		};

		this.leftHFContainer = new HFContainer();
		this.centerHFContainer = new HFContainer();
		this.rightHFContainer = new HFContainer();

		this.leftHFContainer.addMouseListener(this.focusMouseListener);
		this.centerHFContainer.addMouseListener(this.focusMouseListener);
		this.rightHFContainer.addMouseListener(this.focusMouseListener);

		this.leftHFContainer.setContentChangeListener(contentChangeListener);
		this.centerHFContainer.setContentChangeListener(contentChangeListener);
		this.rightHFContainer.setContentChangeListener(contentChangeListener);
		paneElementContainer.add(createContainerSection("左区域:", this.leftHFContainer));
		paneElementContainer.add(createContainerSection("中间区域:", this.centerHFContainer));
		paneElementContainer.add(createContainerSection("右区域:", this.rightHFContainer));

		setCurrentHFContainer(this.leftHFContainer);
	}

	private HFInsertButton createHFInsertButton(HFElement element) {
		HFInsertButton insertButton = new HFInsertButton(element);
		insertButton.addActionListener(this.insertActionListener);

		return insertButton;
	}

	private JPanel createContainerSection(String caption, HFContainer container) {
		JPanel panel = new JPanel();

		panel.setLayout(new BorderLayout());
		JLabel title = new JLabel(caption);
		panel.add(title, BorderLayout.NORTH);
		title.setHorizontalAlignment(SwingConstants.LEFT);

		panel.add(new JScrollPane(container), BorderLayout.CENTER);
		return panel;
	}

	public void populate(ReportHF reportHF) {
		if (reportHF == null)
			reportHF = new ReportHF();

		this.setHfHeight(UnitUtils.inch2mm(reportHF.getHeight()));

		this.leftHFContainer.populate(reportHF.getLeftList());
		this.centerHFContainer.populate(reportHF.getCenterList());
		this.rightHFContainer.populate(reportHF.getRightList());

		refresh();
	}

	public ReportHF update() {
		ReportHF hf = new ReportHF();

		hf.setHeight(UnitUtils.mm2inch(this.getHfHeight()));
		hf.setLeftList(this.leftHFContainer.update());
		hf.setCenterList(this.centerHFContainer.update());
		hf.setRightList(this.rightHFContainer.update());

		return hf;
	}

	private void refresh() {
		ReportHF hf = update();
		this.hfHeight = this.headFootUnitFieldPane.getValue();
		this.hfPreviewPane.refreshReportHFPaintable(hf, (int) this.hfWidth, UnitUtils.inch2pixel(UnitUtils
				.mm2inch(this.headFootUnitFieldPane.getValue())), 1, 100, 1, 100);

		this.updateUI();
	}

	private void setCurrentHFContainer(HFContainer container) {
		this.currentHFContainer = container;
		this.currentHFContainer.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
	}

	public void setHfHeight(double hfHeight) {
		this.hfHeight = hfHeight;
		this.headFootUnitFieldPane.setValue(hfHeight);
	}

	public double getHfHeight() {
		return hfHeight;
	}

	private class AdjustHeightPane extends JPanel {
		/**
		 * UID
		 */
		private static final long serialVersionUID = -273271775517468808L;
		private JSpinner valueSpinner;

		public AdjustHeightPane() {
			setLayout(new FlowLayout(0, 3, 0));
			SpinnerNumberModel model = new SpinnerNumberModel(0.0D, 0.0D, Integer.MAX_VALUE, 1.0D);
			this.valueSpinner = new JSpinner(model);
			GuiUtils.setColumnForSpinner(this.valueSpinner, 4);
			add(this.valueSpinner);

			model.addChangeListener(new ChangeListener() {
				public void stateChanged(ChangeEvent evt) {
					HeaderFooterEditPane.this.refresh();
				}

			});
			JLabel lblUnit = new JLabel();
			lblUnit.setText("毫米");
			Dimension dimUnit = new Dimension(lblUnit.getPreferredSize().width,
					this.valueSpinner.getPreferredSize().height);
			lblUnit.setMinimumSize(dimUnit);

			lblUnit.setSize(dimUnit);
			lblUnit.setPreferredSize(dimUnit);
			add(lblUnit);
		}

		private double getValue() {
			return ((Number) this.valueSpinner.getValue()).doubleValue();
		}

		private void setValue(double value) {
			this.valueSpinner.setValue(value);
		}
	}

	private static class HFInsertButton extends JButton {
		/**
		 * UID
		 */
		private static final long serialVersionUID = 7567800363557992230L;
		private HFElement hfElement;

		public HFInsertButton(HFElement hfElement) {
			setHFElement(hfElement);
		}

		private void initAttributes() {
			setIcon(this.hfElement.getIcon());
			setToolTipText(this.hfElement.getCaption());
		}

		public HFElement getHFElement() {
			return this.hfElement;
		}

		public void setHFElement(HFElement element) {
			this.hfElement = element;
			initAttributes();
		}
	}

	private class HFPreviewPane extends JPanel implements Scrollable {
		/**
		 * UID
		 */
		private static final long serialVersionUID = -7042339815254415294L;
		private int borderWidth;
		private int borderHeight;
		private ReportHF reportHF;
		private int hfWidth;
		private int hfHeight;
		private int pageNum;
		private int totalPages;
		private int groupPageNum;
		private int groupTotalPages;

		public HFPreviewPane() {
			this(new ReportHF(), 500, 0, 1, 100, 1, 100);
		}

		public HFPreviewPane(ReportHF hf, int width, int height, int pageNum, int totalPages, int groupPageNum,
				int groupTotalPages) {
			this.borderWidth = 8;
			this.borderHeight = 20;
			this.reportHF = null;

			refreshReportHFPaintable(hf, width, height, pageNum, totalPages, groupPageNum, groupTotalPages);
		}

		public void refreshReportHFPaintable(ReportHF hf, int width, int height, int pageNum, int totalPages,
				int groupPageNum, int groupTotalPages) {
			this.reportHF = hf;
			this.hfWidth = width;
			this.hfHeight = height;
			this.pageNum = pageNum;
			this.totalPages = totalPages;
			this.groupPageNum = groupPageNum;
			this.groupTotalPages = groupTotalPages;
		}

		public void paintComponent(Graphics g) {
			super.paintComponent(g);

			if (this.reportHF == null)
				return;

			Graphics2D g2 = (Graphics2D) g;
			Dimension dim = getSize();

			if (isEnabled()) {
				g2.setPaint(Color.WHITE);
			} else {
				g2.setPaint(SystemColor.control);
			}

			g2.fill(new Rectangle2D.Double(0.0D, 0.0D, dim.getWidth(), dim.getHeight()));
			if (!isEnabled()) {
				return;
			}

			Rectangle2D rect = new Rectangle2D.Double(Math.max(0.0D, (dim.getWidth() - this.hfWidth) / 2.0D),
					this.borderHeight, this.hfWidth, this.hfHeight);
			g2.setPaint(Color.BLACK);

			GraphHelper.draw(g2, new Rectangle2D.Double(rect.getX() - 1.0D, rect.getY() - 1.0D, rect.getWidth() + 1.0D,
					rect.getHeight() + 1.0D), 3);

			this.reportHF.paint(g2, rect, this.hfWidth, this.pageNum, this.totalPages, this.groupPageNum,
					this.groupTotalPages);
		}

		public Dimension getPreferredSize() {
			if (this.reportHF == null)
				return super.getPreferredSize();
			return new Dimension(this.borderWidth * 2 + this.hfWidth, this.borderHeight * 2 + this.hfHeight);
		}

		public Dimension getPreferredScrollableViewportSize() {
			return getPreferredSize();
		}

		public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
			switch (orientation) {
			case SwingConstants.VERTICAL:
				return (visibleRect.height / 10);
			case SwingConstants.HORIZONTAL:
				return (visibleRect.width / 10);
			}
			throw new IllegalArgumentException("无效的方向: " + orientation);
		}

		public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
			switch (orientation) {
			case 1:
				return visibleRect.height;
			case 0:
				return visibleRect.width;
			}
			throw new IllegalArgumentException("无效的方向: " + orientation);
		}

		public boolean getScrollableTracksViewportWidth() {
			if (getParent() instanceof JViewport)
				return (getParent().getWidth() > getPreferredSize().width);
			return false;
		}

		public boolean getScrollableTracksViewportHeight() {
			if (getParent() instanceof JViewport)
				return (getParent().getHeight() > getPreferredSize().height);
			return false;
		}
	}
}